from threading import Thread
import threading
from simpledcpp.core.settings import Settings
import socket
import sys
import time
import psyco
try:
	import pynotify
	NOTIFY_ENABLED = True
except:
	NOTIFY_ENABLED = False
import urllib2
ST_SOCKET_OK = 0
ST_SOCKET_ER = 1
ST_SOCKET_TM = 2
SOCKET_DEBUG = False
#SOCKET_DEBUG = True
	
class BaseDCPPThread(Thread):
	""" A subclass of threading.Thread, with a kill method. """
	def __init__(self, *args, **keywords):
		Thread.__init__(self, *args, **keywords)
		self.killed = False
#	def start(self):
#		""" Start thread """
#		self.__run_backup = self.run
#		self.run = self.__run #Force the thread install our trace.

#	def __run(self):
#		""" Hacked run function """
#		sys.settrace(self.globaltrace)
#		self.__run_backup()
#		self.run = self.__run_backup

#	def globaltrace(self, frame, why, arg):
#		if why == "call":
#			return self.localtrace
#		else:
#			return None

#	def localtrace(self, frame, why, arg):
#		if self.killed:
#			if why == 'line':
#				raise SystemExit()
#				return self.localtrace

	def kill(self):
		self._Thread__stop()
		self.killed = True


class DCPPThread(BaseDCPPThread):
	def __init__(self, *args, **keywords):
		BaseDCPPThread.__init__(self, *args, **keywords)

	def run(self):
		self.retval = self.userrun()
	def setFunc(self, func):
#		print func
		self.userrun = func

def start_new_thread(func):
        t = DCPPThread()
        t.setFunc(func)
        t.start()
        return t

class DCPPTCPSocket:
	def __init__(self, DEBUG = False, FROM_SOCKET = None):
		global ST_SOCKET_OK
		if FROM_SOCKET != None:
			self._socket = FROM_SOCKET
		self.DEBUG = DEBUG
		self.status = ST_SOCKET_OK
#		self._lock = threading.Lock()

	def Connect(self, addr, TIMEOUT = 30):
		global ST_SOCKET_TM, ST_SOCKET_ER, ST_SOCKET_OK
		if TIMEOUT < 1: TIMEOUT = 30
		self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self._socket.settimeout(TIMEOUT)
		self._addr = addr
		self._connect()
		return
				
	def ok(self):
		global ST_SOCKET_OK
		if self.status == ST_SOCKET_OK:
			return True
		else:
			return False

	def Recieve(self, TIMEOUT = 30):
		if TIMEOUT < 1: TIMEOUT = 30
		try:
			self._socket.settimeout(TIMEOUT)
		except:
			pass
		data = self._recv()
		return data
		
	def Close(self):
		while True:	
			try:
				self._socket.close()
				return 
			except:
				print sys.exc_info()
			time.sleep(0.1)

        def _connect(self):
                global ST_SOCKET_OK, ST_SOCKET_ER, ST_SOCKET_TM
                try:
                        self._socket.connect(self._addr)
                        self.status = ST_SOCKET_OK
		except socket.timeout:
			self.status = ST_SOCKET_TM
                except:
			if self.DEBUG:
				print "On function _connect: exception:"
				print sys.exc_info()
				print "Exception end."
                        self.status = ST_SOCKET_ER

	def _recv(self):
		global ST_SOCKET_OK, ST_SOCKET_ER, ST_SOCKET_TM, SOCKET_DEBUG
		try:
			data = self._socket.recv(1024)
			if len(data) == 0:
				self.status = ST_SOCKET_ER
				return None
			self.status = ST_SOCKET_OK
			if SOCKET_DEBUG:
				print "<< %s"%data
			return data
		except socket.timeout:
			self.status = ST_SOCKET_TM
			return None
		except:
			if self.DEBUG:
				print "On function _recv: exception:"
				print sys.exc_info()
				print "Exception end."
			self.status = ST_SOCKET_ER
			return None

	def Send(self, data, enc = True):
		global ST_SOCKET_OK, ST_SOCKET_ER, SOCKET_DEBUG
		try:
			if enc:
				data = data.encode('utf-8')
		except:
			pass
		try:
			self._socket.sendall(data)
#			sended = self._socket.send(data)
#			while sended < len(data):
#				sended = sended + self._socket.send(data[sended:])
			self.status = ST_SOCKET_OK
			if SOCKET_DEBUG:
				print ">> \"%s\""%data
		except:
			if self.DEBUG:
				print "In function _send: exception:"
				print sys.exc_info()
				print "Exception end."
			self.status = ST_SOCKET_ER

class DCPPPart:
	def __init__(self, parent):
		if parent != None:
			try:
				self.settings = parent.settings
			except:
				self.settings = Settings(None)
				print _("Settings don't work.")
			try:
				self.filelist = parent.filelist
			except:
				self.filelist = {}
#				print _("Filelist don't work")
			try:
				self.Events = parent.Events
				self.Events.Subscribe('ON_SYSTEM_SHUTDOWN',self.stop)
			except:
				print sys.exc_info()
				print _("Events may be don't work.")
			try:
				self.queue = parent.queue
			except:
				pass
				#print sys.exc_info()
				#print "Queue may be don't work correctly"
		else:
			self.settings = Settings(None)
			print _("Settings unaviable.")
		self.parent = parent
	def _genMagnet(self, filename, filesize, tth):
		return 'magnet:?xl=%s&dn=%s&xt=urn:tree:tiger:%s'%(filesize,urllib2.quote(filename),tth)

	def Event(self, Event):
		try:
			self.parent.Event(Event)
		except:
			pass

	def Notify(self, subject, message, TIMEOUT = None):
		global NOTIFY_ENABLED
		if int(self.settings.get('NotifyEnabled', 1)) and NOTIFY_ENABLED:
			n = pynotify.Notification(subject, message)
			if TIMEOUT == None:
				n.set_timeout(int(self.settings.get("NotifyTime",TIMEOUT))*1000)
			else:
				n.set_timeout(int(TIMEOUT) * 1000)
			n.show()

	def stop(self):
		pass

	def from_utf8(self, text, codepage = 'cp1251'):
		try:
			u = unicode(text, 'utf8')
			converted_text = u.encode(codepage)
			return converted_text
		except:
			return text

	def to_utf8(self, text, codepage = 'cp1251'):
		try:
			u = unicode(text, codepage)
			return u.encode('utf8')
		except:
			return text
		
	def utf8_cp1251(self,text):
    		u=unicode(text, 'utf8')
		cyrillic_cp1251=u.encode('cp1251')
		return cyrillic_cp1251

	def cp1251_utf8(self,text):
		cyrillic_cp1251=unicode(text, 'cp1251')
		text=cyrillic_cp1251.encode('utf8')
		return text

class DCPPManager(DCPPPart):
	def __init__(self, parent, DEBUG = False):
		DCPPPart.__init__(self, parent)
		self.elements = {}
		self.eid = 0
		self.DEBUG = DEBUG

	def add(self, Element):
		self.eid = self.eid + 1
		self.elements[self.eid] = Element
		return self.eid

	def remove(self, Eid = None):
		try:
			self.elements.pop(Eid)
		except:
			if self.DEBUG:
				print "In DCPPManager::remove exception:"
				print sys.exc_info()
				print "End exception."

	def isExists(self, Element):
		for i in self.elements:
			if self.elements[i] == Element:
				return i
		return False

class DCPPEvent:
	def __init__(self, event, userdata = None):
		if (not isinstance(userdata, tuple)) and (userdata != None):
			print "FAILED CREATE EVENT \"%s\". Userdata is not a tuple."%event
			self.event = event
			self.userdata = (userdata,)
			return None
		self.event = event
		self.userdata = userdata

def with_psyco(f):
        g = psyco.proxy(f)
        return g

